const express = require('express');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const session = require('express-session');
const cors = require('cors');
const axios = require('axios');
const app = express();

const debug = require('debug')('fe-sso:server');
const http = require('http');
const $ = require('./config');

function modify (config) {
  let originStep = [];
  config.cors.origin.forEach(item => {
    originStep.push(new RegExp(item));
  });
  config.cors.origin = originStep;
  return config;
}
function reqFormPC (userAgent) {
    if (!userAgent) return {};
    let Sys = {};
    let ua = userAgent.toLowerCase();
    let s;
    s = ua.match(/msie ([\d.]+)/);
    if (s) Sys.ie = s[1];
    s = ua.match(/firefox\/([\d.]+)/);
    if (s) Sys.firefox = s[1];
    s = ua.match(/chrome\/([\d.]+)/);
    if (s) Sys.chrome = s[1];
    s = ua.match(/opera.([\d.]+)/);
    if (s) Sys.opera = s[1];
    s = ua.match(/version\/([\d.]+).*safari/);
    if (s) Sys.safari = s[1];
    return Sys;
}
function corsHeader (res) {
    res.setHeader('Access-Control-Allow-Credentials', 'true');
    res.setHeader('Access-Control-Allow-Methods', 'POST,GET,OPTIONS,PUT,DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'cache-control,content-type,hash-referer,x-requested-with');
}

$.then(function (response) {
  const Config = modify(response.data);
  if (!Config) {
    return console.error('未能获取到对应的Config！');
  }
  let {
    LocalURL,
    SSO,
    Projects,
    Java,
    user,
  } = Config;

  const {
    login,
    logout,
    ssoOrigin,
    checkTicket,
    loginMethod,
    logoutMethod,
    checkTicketMethod
  } = SSO;

  /***
   * Enable All CORS Requests
   **/
  app.use(cors(Config.cors));
  app.use(function (req, res, next) {
        if ((new RegExp(login)).test(req.url)) {
            let userAgent = req.headers['user-agent'];
            let PC = reqFormPC(userAgent);
            console.log(`${(new Date()).toLocaleString()}  ${req.ip}  ${JSON.stringify(PC)}  登陆`);
            let {chrome} = PC;
            if (!chrome) {
                corsHeader(res);
            } else {
                let version = chrome.split('.')[0];
                if (version < 62) {
                    corsHeader(res);
                }
            }
        }
        next();
    });

  /***
   * 启用 session
   **/
  app.use(session(Config.session));

  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: false }));
  app.use(cookieParser());

  const router = express.Router();
  router[loginMethod](login, async (req, res, next) => {
    let url = '';
    let origin = req.body.origin;
    let port = req.body.port;
    let ie6 = false;
    delete req.body.origin;
    delete req.body.port;
    if (req.body.user) {
      for (let i = 0; i<user.length; i++) {
        if (user[i].userName === req.body.user) {
          url = user[i];
        }
      }
      delete req.body.user;
    }
    if (req.body.ie6) {
        ie6 = true;
      delete req.body.ie6;
    }
    try {
      let response = await axios({
        method: loginMethod,
        // url: ssoLogin,
        url: Java.url + login,
        headers: {
          'client_ip': req.ip,
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36',
          'Content-Type': 'application/json;charset=UTF-8'
        },
        data: req.body,
      });
      req.session.JSESSIONID = response.headers['set-cookie'][0].split(';')[0].split('=')[1];
      if (response.data.ticket !== 'ticket') req.session.save();
      let Project = Projects[req.body.appCode];
      url = url ?
          `http://${(Projects['devJava'].PublicURL || Projects['devJava'].LocalURL).origin}:${(Projects['devJava'].PublicURL || Projects['devJava'].LocalURL).port}/${Project.Project.name}/${encodeURI(url.userName)}/${Project.Project.userInfo}?ticket=${response.data.ticket || 'ticket'}&ckcode=${response.data.ckcode || 'ckcode'}`:
          (Project.Project.name ?
              `http://${origin || (Project.PublicURL || Project.LocalURL).origin}:${port || (Project.PublicURL || Project.LocalURL).port}/${Project.Project.name}/${Project.Project.userInfo}?ticket=${response.data.ticket || 'ticket'}&ckcode=${response.data.ckcode || 'ckcode'}` :
              `http://${origin || (Project.PublicURL || Project.LocalURL).origin}:${port || (Project.PublicURL || Project.LocalURL).port}/${Project.Project.userInfo}?ticket=${response.data.ticket || 'ticket'}&ckcode=${response.data.ckcode || 'ckcode'}`);
      return ie6 ? res.json({url}): res.redirect(url);
    } catch (err) {
      console.log(err);
      let Project = Projects[req.body.appCode];
      return res.redirect(`http://${origin || (Project.PublicURL || Project.LocalURL).origin}:${port || (Project.PublicURL || Project.LocalURL).port}/${Project.Project.name}/${Project.Project.userInfo}?ticket=${response.data.ticket || 'ticket'}&ckcode=${response.data.ckcode || 'ckcode'}`);
    }
  });
  router[logoutMethod](logout, async (req, res, next) => {
    let logoutUrl = Java.url + logout;
    if (req.session.JSESSIONID) {
      try {
        let response = await axios({
          method: logoutMethod,
          url: logoutUrl,
          headers: {
            'Cookie': `JSESSIONID=${req.session.JSESSIONID};`,
            'client_ip': req.ip,
          },
          data: req.body
        });
        req.session.destroy();
        return res.send(response.data);
      } catch (err) {
        console.log(err);
        return res.send(err);
      }
    } else {
      return res.json({
        "messageType": 1,
        "type": "error",
        "title": "提示信息",
        "message": "请先登录",
        "url": "/"
      });
    }
  });
  router[checkTicketMethod](checkTicket, async (req, res, next) => {
    if (!req.query.url || !req.query.appcode || !req.query.login) {
      return res.json({
        "messageType": 1,
        "type": "error",
        "title": "提示信息",
        "message": "错误的请求 URL 或者 Login 或者 appCode 丢失",
        "url": "/"
      });
    }
    const logout = `${req.query.login}?userLogin=false`;
    if (req.session.JSESSIONID) {
      let Project = Projects[req.query.appcode];
      try {
        let response = await axios({
          method: 'get',
          url: Java.url + '/sso/checkTicket',
          headers: {
            'Cookie': `JSESSIONID=${req.session.JSESSIONID};`,
            'client_ip': req.ip,
          },
          data: req.body
        });
        let {
          ticket,
          ckcode,
        } = response.data;
        if (ticket === 'ticket') {
          delete req.session.JSESSIONID;
          req.session.save();
          console.log(`- ${(new Date()).toLocaleTimeString()}  --------------------`);
          console.log(req.query.url);
          console.log(logout);
          console.log('----------------------------------------------------------------------------');
          return res.redirect(logout);
        }
        let redirectUrl = `http://${(Project.PublicURL || Project.LocalURL).origin}:${(Project.PublicURL || Project.LocalURL).port}${req.query.url}?ticket=${ticket || 'ticket'}&ckcode=${ckcode || 'ckcode'}`;
        console.log(redirectUrl);
        return res.redirect(redirectUrl);
      } catch (err) {
        console.log(err);
        return res.send(err);
      }
    } else {
      console.log(`- ${(new Date()).toLocaleTimeString()}  --------------------`);
      console.log(req.query.url);
      console.log(logout);
      console.log('----------------------------------------------------------------------------');
      return res.redirect(logout);
    }
  });

  app.use(router);

  /**
   * NodeJS 服务启动
   */

  const port = normalizePort(process.env.PORT || LocalURL.port);
  const host = (process.env.HOST || LocalURL.origin);
  app.set('port', port);

  /**
   * Create HTTP server.
   */

  const server = http.createServer(app);

  /**
   * Listen on provided port, on all network interfaces.
   */

  server.listen(port, host);
  console.log('Server listening on ' + host + ':' + port); // eslint-disable-line no-console
  server.on('error', onError);
  server.on('listening', onListening);

  /**
   * Normalize a port into a number, string, or false.
   */

  function normalizePort(val) {
    let port = parseInt(val, 10);

    if (isNaN(port)) {
      // named pipe
      return val;
    }

    if (port >= 0) {
      // port number
      return port;
    }

    return false;
  }

  /**
   * Event listener for HTTP server "error" event.
   */

  function onError(error) {
    if (error.syscall !== 'listen') {
      throw error;
    }

    let bind = typeof port === 'string'
      ? 'Pipe ' + port
      : 'Port ' + port;

    // handle specific listen errors with friendly messages
    switch (error.code) {
      case 'EACCES':
        console.error(bind + ' requires elevated privileges');
        process.exit(1);
        break;
      case 'EADDRINUSE':
        console.error(bind + ' is already in use');
        process.exit(1);
        break;
      default:
        throw error;
    }
  }

  /**
   * Event listener for HTTP server "listening" event.
   */

  function onListening() {
    let addr = server.address();
    let bind = typeof addr === 'string'
      ? 'pipe ' + addr
      : 'port ' + addr.port;
    debug('Listening on ' + bind);
  }
});
